<?php

class dbconf
{

	protected $link_id		= 0;
	protected $query_id		= 0;
	public $record		= array();
	protected $errno		= 0;
	protected $error		= "";
	
	/* Array fort sort / order by */
	protected $sort;
	
	/* Limit string */
	protected $limit;
	
	/* Columns for queries */
	protected $cols;
	
	/* Use distinct */
	protected $distinct = false;
	
	/* Values and column names for insert and update */
	protected $valueData = array();
	
	/* Table */
	protected $table;
	
	/* Holder for SQL query string */
	protected $query;
	
	/* Get QUERY hodler */
	private $queryString;
		
	/* Holder for JOIN statements */
	protected $join = array();
	
	/* Column prefix */
	protected $colPrefix;


	/**
	 * Constructor, connect to host/db and select database.
	 * Also select table to use in query if this is
	 * specified.
	 * 
	 * @param $table Table to use in query
	 *
	 * @access public
	 *
	 */
	public function __construct($table = null)
	{

		$this->connect();
		$this->selectDb($this->db_name);
		
		if ( $table != null )
		{
		
			$this->setTable(DBPREFIX.$table);
		
		}

	}


	/**
	 * Destructor, close database connection
	 *
	 * @access public
	 *
	 */
	public function __destruct()
	{

		//$this->close();

	}


	/**
	 * Connect to MYSQL
	 *
	 * @return resource link_id
	 *
	 * @access public
	 *
	 */
	public function connect()
	{
			include(ROOT."pref.php");
			$this->db_host = $db_host;
			$this->db_user = $db_user;
			$this->db_password = $db_pass;
			$this->db_name = $db_name;
		if(!is_resource($this->link_id))
		{
			if(!$this->pconnect)
			{
				$this->link_id = mysql_connect($this->db_host, $this->db_user, $this->db_password, $this->new_link, $this->client_flags);
			}
			else
			{
				$this->link_id = mysql_pconnect($this->db_host, $this->db_user, $this->db_password, $this->client_flags);
			}

	      	if(!$this->link_id)
    	  	{
				$this->halt("False link id, DB connect failed");
			}
			
			mysql_set_charset("utf8", $this->link_id);
			
		}

		return $this->link_id;

	}


	/**
	 * Select DB
	 *
	 * @param string $db - Database name
	 *
	 * @access public
	 *
	 */
	public function selectDb($db)
	{

		if(!mysql_select_db($db, $this->link_id))
		{
			$this->halt("Can not use database ".$this->db_name);
		}

	}


	/**
	 * Close MYSQL connection
	 *
	 * @access public
	 *
	 */
	public function close()
	{

		if(is_resource($this->link_id) && !$this->pconnect)
		{
			mysql_close($this->link_id);
		}

		$this->link_id = null;

	}


	/**
	 * MYSQL query
	 *
	 * @param string $sql - Query
	 *
	 * @access public
	 *
	 * @return resource query_id
	 *
	 */
	public function query($sql = null)
	{

		if(empty($sql))
		{
			return false;
		}

		if($this->auto_free)
		{
			$this->freeResult();
		}

		$this->query_id = mysql_query($sql, $this->link_id);

		if(!$this->query_id)
		{
		
			$this->errno = mysql_errno($this->link_id);
			$this->error = mysql_error($this->link_id);
			$this->halt("Invalid SQL: ".$sql);
			
		}

		return $this->query_id;

	}

	/**
	 * function select()
	 * 
	 * @param $table Database table name to select from
	 * 
	 * @param $additionalStatement More custom where statements,
	 * and whatever you want to do.
	 *
	 * @access public
	 * 
	 * @return void
	 */
	public function select($additionalStatement = "")
	{

		/* Start building query */
		$this->query  = "SELECT ";

		/* Remove any written "WHERE" */
		$where = str_ireplace("where", "", $additionalStatement);

		/* If setDistinct() has been called */
		$this->query .= ( $this->distinct ) ? "DISTINCT " : "";

		/* Write cols for select */
		$this->query .= ( isset($this->cols) ) ? $this->table . "." . implode(", " . $this->table . ".", $this->cols) . " \n" : "* ";

		/* Table selection */
		$this->query .= "FROM " . $this->table . "\n";

		/* Add JOIN statement */
		$this->query .= ( count($this->join > 0) ) ? implode("\n", $this->join) . "\n" : "";

		/**
		 * Additional statment for the query. Mostly
		 * used for WHERE statement, advanced JOINS
		 * and so on.
		 */
		$this->query .= ($additionalStatement != "") ? "WHERE " . $where . "\n" : "";

		/* Write sort / order by strings */
		$this->query .= ( is_array($this->sort) ) ? " ORDER BY " . implode(",", $this->sort) : "";

		/* Write limit to query */
		$this->query .= ( isset($this->limit) ) ? " LIMIT " . $this->limit : "";

			/* .. and run the query! */
			$this->query($this->query );

		
	}
	
	/**
	 * function insert()
	 * 
	 * Insert data to database
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function insert()
	{
	
		/* Count the values in value array s*/
		$numCols = count($this->valueData);
		
		/* If any values are set */
		if ($numCols > 0)
		{

			/* Flip array and get column names */
			$colNames = $this->getColNames($this->valueData);
			
			/* Set col values, and use mysql_real_escape_string och every value */
			$colValues = array_map(array($this, "escape"), $this->valueData);
		
			/* Begin writing query */
			$this->query  = "INSERT INTO ";
			
			/* Write table name*/
			$this->query .= $this->table;
			
			/* Write column names*/
			$this->query .= " (";
			$this->query .= ( isset($this->colPrefix) ) ? $this->colPrefix : ""; 
			$this->query .= ( isset($this->colPrefix) ) ? implode(", " . $this->colPrefix , $colNames) : implode(", ", $colNames);
			
			/* Wrtie values */
			$this->query .= ") VALUES ('";
			$this->query .= implode("', '", $colValues);
			$this->query .= "') ";
			
			/* .. and run query! */
			$this->query($this->query);
		
		}
		else
		{
		
			trigger_error("No values set for insertion. Use \$db->column_name = \"value\";", E_USER_ERROR);
		
		}
	
	}

	/**
	 * function update()
	 * 
	 * @param $whereStatement WHERE statement. Write
	 * "all" if you want to update all rows
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function update($whereStatement = "")
	{

		/* Number of columns to update */
		$numCols = count($this->valueData);
		
		/* Remove any written "WHERE" */
		$where = str_ireplace("where", "", $whereStatement);
	
		/* Escape values */
		$valueData = array_map(array($this, "escape"), $this->valueData);
		
		/* Only run query if values are set */
		if ( $numCols > 0 )
		{

			/* Begin writing query */
			$this->query  = "UPDATE ";
			$this->query .= $this->table;
			$this->query .= " SET\n";
				
			/* Counter */
			$c = 1;
				
			/* Write columns and values */
			foreach ($valueData as $col => $val)
			{
				
				$this->query .= ( isset($this->colPrefix) ) ? $this->colPrefix . $col . " = '" . $val . "'" : $col . " = '" . $val . "'";
				$this->query .= ( $c < $numCols ) ? ",\n" : "";
				
				$c++;
				
			}
				
			$this->query .= "\n";
		
			/* If where statement is not "all" */
			if($where != ""){if (strtolower($where) != "all")
			{

				$this->query .= "WHERE " . $where;

			}
			}
			/* Set limit */
			$this->query .= ( isset($this->limit) ) ? "\nLIMIT " . $this->limit : "";

			/* .. and run query! */
			$this->query($this->query);
			
		}
		else
		{
		
			trigger_error("No values set for update. Use \$db->column_name = \"value\";", E_USER_ERROR);
		
		}
	
	}
	
	/**
	 * function delete()
	 * 
	 * Delete data from database
	 * 
	 * @param $whereStatement WHERE string
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function delete($whereStatement)
	{

		/* Remove any written "WHERE" */
		$where = str_ireplace("where", "", $whereStatement);

		/* Build query string */
		$this->query  = "DELETE FROM ";
		$this->query .= $this->table;
		$this->query .= " WHERE " . $where;
		
		/* .. and run query! */
		$this->query($this->query);
	
	}

	/**
	* Get column names from data value
	* array.
	* 
	* @param $colArray Array with columns (keys)
	* and values.
	* 
	* @access private
	* 
	* @return Array with column names
	*/
	private function getColNames($colArray)
	{
	
		$colNames = array();
	
		foreach ($colArray as $col => $val)
		{
	
			$colNames[] = $col;
	
		}
	
		return $colNames;
	
	}
	
	/**
	 * Get query string
	 * 
	 * @access public
	 * 
	 * @return DB Query string
	 */
	public function getQuery()
	{

		$this->getQuery = true;
	
	}
	
	/**
	 * function setTable()
	 * 
	 * Set table name for query string
	 * 
	 * @param $tableName The name of the DB table
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function setTable($tableName)
	{
	
		$this->table = $tableName;
	
	}
	
	/**
	 * function setCols()
	 * 
	 * @param $cols Array with columns to use for
	 * SQL query
	 * @param $prefix Set prefix directly when
	 * setting columns to use
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function setCols($cols, $prefix = null)
	{

		/* Use the specified array directly */
		if ( is_array($cols) )
		{
	
			/* Set columns */
			$this->cols = $cols;
			
			/* Set column prefix if specified */
			if ( $prefix != null )
			{
		
				$this->setColPrefix($prefix);
		
			}
			
		}
		/* .. or else just add to the array */
		else
		{
			
			/* Add column to the column array */
			$this->setCol($cols);
		
		}
		
	}
	
	/**
	 * functioun setCol()
	 * 
	 * Add single column to the column array
	 * 
	 * @param $col Column name
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function setCol($col)
	{
	
		$this->cols[] = $col;
	
	}

	/**
	 * function set ColPrefix()
	 * 
	 * Set column prefix that will automaticly
	 * be added to every column name
	 * 
	 * @param $prefix The prefix
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function setColPrefix($prefix)
	{
	
		/* Set prefix property */
		$this->colPrefix = $prefix;
		
		/* Check if any cols is set */
		if ( is_array($this->cols) )
		{
	
			/* Add prefix */
			foreach ($this->cols as $key => $value)
			{
			
				$this->cols[$key] = $prefix . $value;
			
			}
			
		}
		
		/* Check if any values for insertion or update exists */
		if ( is_array($this->valueData) )
		{
	
			foreach ($this->valueData as $key => $value)
			{
			
				$this->valueData[$prefix . $key] =  $value;
				unset($this->valueData[$key]);
			
			}
			
		}
	
	}
	
	/**
	 * function setSort()
	 * 
	 * @param $sort Sort / order by string. Must be a string.
	 * If you want to add more sorting options, just run this
	 * method several times. The string will be added to the 
	 * internal class sort array.
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function setSort($sort)
	{
	
		$this->sort[] = $sort;
	
	}

	/**
	 * function setSort()
	 * 
	 * @param $sort Sort / order by string. Must be a string.
	 * If you want to add more sorting options, just run this
	 * method several times. The string will be added to the 
	 * internal class sort array.
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function unsetSort()
	{
	
		$this->sort = array();
	
	}

	/**
	 * function setOrder()
	 * 
	 * This function exists only because you can use three
	 * different names for adding the "sort" or "order by".
	 * setSort, setOrder and setOrderBy
	 * 
	 * @param @sort See function setSort in this class
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function setOrder($sort) { $this->setSort($sort); }

	public function unsetOrder() { $this->unsetSort(); }

	/**
	 * function setOrder()
	 * 
	 * This function exists only because you can use three
	 * different names for adding the "sort" or "order by".
	 * setSort, setOrder and setOrderBy
	 * 
	 * @param @sort See function setSort in this class
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function setOrderBy($sort) { $this->setSort($sort); }

	public function unsetOrderBy() { $this->unsetSort(); }

	/**
	 * function setDistinct()
	 * 
	 * Sets query to SELECT DISTINCT
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function setDistinct()
	{
	
		$this->distinct = true;
	
	}
	
	/**
	 * function setLimit
	 * 
	 * Set the limit for the SQL query
	 * 
	 * @param $value The limit string value
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function setLimit($value)
	{
	
		$this->limit = $value;
	
	}

	/**
	 * function setLimit
	 * 
	 * Set the limit for the SQL query
	 * 
	 * @param $value The limit string value
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function unsetLimit()
	{
	
		$this->limit = null;
	
	}

	/**
	 * function __get()
	 * 
	 * This function is used for getting
	 * values from the database. Instead of
	 * using $db->f("col_name"), you can now
	 * use $db->col_name.
	 * 
	 * @param $col Column name
	 * 
	 * @access public
	 * 
	 * @return Column value from database
	 * 
	 */
	public function __get($col)
	{
	
		if ( isset($this->colPrefix) )
		{
		
			return $this->f($this->colPrefix . $col);
		
		}
		else
		{
	
			return $this->f($col);
			
		}
	
	}
	
	/**
	 * function __set()
	 * 
	 * This function is used to set values when
	 * using DB::insert() or DB::update()
	 * 
	 * @param $key Column name
	 * @param $val Column value
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function __set($key, $val)
	{
	
		$this->valueData[$key] = $val;
	
	}

	/**
	 * Set JOIN statement
	 * 
	 * @param $type Join type (LEFT, RIGHT, INNER ..)
	 * @param $table Table to join with
	 * @param $tableAndColA Table.ColNameA
	 * @param $tableAndColB Table.ColNameB
	 * 
	 * @access Public
	 * 
	 * @return void
	 */
	public function join($type, $table, $tableAndColA, $tableAndColB)
	{
	
		$this->join[]  = $this->getJoinType($type) . " " . $table . " ON " . $tableAndColA . " = " . $tableAndColB;
	
	}
	
	/**
	 * Set JOIN statement
	 * 
	 * @param $joinStatement The JOIN statement
	 * 
	 * @access public
	 * 
	 * @return void
	 */
	public function joinStatement($joinStatement)
	{
	
		$this->join[] = $joinStatement;
	
	}
	
	/**
	 * Get JOIN type string
	 * 
	 * @param $key Type key
	 * 
	 * @access private
	 * 
	 * @return Beginning of JOIN statement string
	 */
	private function getJoinType($key)
	{
	
		$key = strtolower($key);
	
		switch ($key)
		{
		
			case "left":
			
				return "LEFT JOIN";
			
			break;
			
			case "inner":
			
				return "INNER JOIN";
			
			break;
			
			case "right":
			
				return "RIGHT JOIN";
			
			break;
		
		}
	
	}
	
	/**
	 * Fetch MYSQL result rows
	 *
	 * @param string $result_type - Result type ("assoc" - associative array, "num" - enumerated array, "both" - both)
	 *
	 * @access public
	 *
	 * @return bool $status
	 *
	 */
	public function nextRecord($result_type = "both")
	{

		if(!$this->query_id)
		{
			$this->halt("next_record() called with no pending query.");

			return false;
		}
		
		switch($result_type)
		{
			case "assoc":
				$this->record = mysql_fetch_assoc($this->query_id);
				break;

			case "num":
				$this->record = mysql_fetch_row($this->query_id);
				break;

			case "both":
				$this->record = mysql_fetch_array($this->query_id, MYSQL_BOTH);
				break;
		}

		$this->errno = mysql_errno($this->link_id);
		$this->error = mysql_error($this->link_id);
		
		$status = is_array($this->record);

		if(!$status && $this->auto_free)
		{
			$this->freeResult();
		}

		return $status;

	}


	/**
	 * Fetch MYSQL result rows (old function name, calls nextRecord())
	 *
	 * @param string $result_type - Result type ("assoc" - associative array, "num" - enumerated array, "both" - both)
	 *
	 * @access public
	 *
	 * @return bool $status
	 *
	 */
	public function next_record($result_type = "both")
	{

		return $this->nextRecord($result_type);

	}


	/**
	 * Escape data to pass to query
	 *
	 * @param string $str - String to escape
	 *
	 * @access public
	 *
	 * @return string escaped string
	 *
	 */
	public function escape($str)
	{

		return mysql_real_escape_string($str, $this->link_id);

	}


	/**
	 * Escape data to pass to query (all, wildcards etc)
	 *
	 * @param string $str - String to escape
	 *
	 * @access public
	 *
	 * @return string escaped string
	 *
	 */
	public function escapeAll($str)
	{

		$str = str_replace("%", "", $str);

		return mysql_real_escape_string($str, $this->link_id);

	}


	/**
	 * Return value from field from current row
	 *
	 * @param string $name - Field name
	 *
	 * @access public
	 *
	 * @return string value
	 *
	 */
	public function f($name)
	{

		return $this->record[$name];

	}

	/**
	 * Return affected rows in query (UPDATE, INSERT, REPLACE and DELETE)
	 *
	 * @access public
	 *
	 * @return int affected rows
	 *
	 */
	public function affectedRows()
	{

		return mysql_affected_rows($this->link_id);

	}

	/**
	 * Return number of rows in query
	 *
	 * @access public
	 *
	 * @return int number of rows
	 *
	 */
	public function numRows()
	{

		return mysql_num_rows($this->query_id);

	}


	/**
	 * Return number of fields in query
	 *
	 * @access public
	 *
	 * @return int number of fields
	 *
	 */
	public function numFields()
	{

		return mysql_num_fields($this->query_id);

	}


	/**
	 * Return table field names
	 *
	 * @param string $table - Table name
	 *
	 * @access public
	 *
	 * @return array table field names
	 *
	 */
	public function fieldNames($table)
	{

		$arr_cols = array();
		$i = 0;

		$this->query("SHOW COLUMNS FROM ".$table);

		while($this->next_record())
		{
			$arr_cols[$i] = $this->f("0");

			$i++;
		}

		return $arr_cols;

	}


	/**
	 * Return DB tables
	 *
	 * @access public
	 *
	 * @return array DB tables
	 *
	 */
	public function tableNames()
	{

		$arr_tables = array();
		$i = 0;

		$this->query("SHOW TABLES FROM ".$this->db_name);

		while($this->next_record())
		{
			$arr_tables[$i] = $this->f("0");

			$i++;
		}

		return $arr_tables;

	}


	/**
	 * Free query result (resource)
	 *
	 * @access private
	 *
	 * @return array DB tables
	 *
	 */
	private function freeResult()
	{

		if(is_resource($this->query_id))
		{
			mysql_free_result($this->query_id);
		}

		$this->query_id = null;

	}


	/**
	 * Halt, DB error handling
	 *
	 * @param string $msg - Error message
	 *
	 * @access private
	 *
	 * @return mixed error message, mail or halt/die of program
	 *
	 */
	private function halt($msg = null)
	{

		$error_message = null;
		$error_message .= "MYSQL_ERROR - ".$this->db_name."<br />\n";
		$error_message .= "<b>Database error:</b> ".$msg."<br />\n";
		$error_message .= "<b>MYSQL Error</b>: ".$this->errno." (".$this->error.")<br />\n";
		$error_message .= "Date: ".date('Y-m-d H:i:s', time())."<br />\n";
		$error_message .= "IP: ".$_SERVER["REMOTE_ADDR"]."\n";

		if($this->email_debug)
		{
			$headers = "From: ".$this->email_to."\n";

			$subject = "MYSQL Error - ".$this->db_name;

			mail($this->email_to, $subject, $error_message, $headers);
		}

		if($this->debug)
		{
			echo $error_message;
		}

		die("This page is unavailable at the moment. Please try again.");

	}

}

?>
